package com.example.annotation.utils;

import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.View;

import com.example.annitaions.szjFind;
import com.example.annitaions.szjIntent;
import com.example.annotation.annotations.szjClickType;
import com.example.annotation.annotations.szjOnClick;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class szjAnnotationUtil {

    private szjAnnotationUtil() {
    }

    private static volatile szjAnnotationUtil instance;

    public static szjAnnotationUtil getInstance() {
        if (instance == null) {
            synchronized (szjAnnotationUtil.class) {
                if (instance == null) {
                    instance = new szjAnnotationUtil();
                }
            }
        }
        return instance;
    }

    public void init(Activity activity) {

        //findViewById
        initFind(activity);

        //getIntent()
        initIntent(activity);

        //onCLick [不推荐]
        //initOnClick1(activity);

        //onClick [推荐,优点:拓展性高,满足开闭原则,缺点:反射印象效率, 建议:使用APT技术 ]
        initOnClick(activity);
    }

    //TODO findViewById
    public void initFind(Activity activity) {
        //获取 Class
        Class<? extends Activity> cls = activity.getClass();

        //getFields 获得自己+父类的成员 不包括 private
        //getDeclaredFields 获得自己的成员(不包括父类,包括 private)

        //获得此类所有的属性
        Field[] fields = cls.getDeclaredFields();
        //遍历这个类中的所有属性
        for (Field field : fields) {
            //判断属性是否被 szjFind 注解
            if (field.isAnnotationPresent(szjFind.class)) {
                //获得注解的实例
                szjFind szjFind = field.getAnnotation(szjFind.class);

                assert szjFind != null;
                //获取 id
                int id = szjFind.value();
                //找到 Id
                View view = activity.findViewById(id);

                //允许操作 private 属性
                field.setAccessible(true);

                try {
                    //反射设置属性的值
                    field.set(activity, view);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //TODO 传值
    public void initIntent(Activity activity) {
        Intent intent = activity.getIntent();
        //判断是否有值传过来
        if (intent.getExtras() == null) {
            throw new RuntimeException("没有检测到值传入");
        }

        //获取到 class 对象
        Class<? extends Activity> cls = activity.getClass();

        //获取到对象上的所有属性
        Field[] fields = cls.getDeclaredFields();

        for (Field field : fields) {
            //判断是否有该属性
            if (field.isAnnotationPresent(szjIntent.class)) {
                //获取到属性上的值
                szjIntent szjIntent = field.getAnnotation(szjIntent.class);

                assert szjIntent != null;
                //如果没有给当前注解 value 就使用属性的 value
                String value = szjIntent.value().equals("") ? field.getName() : szjIntent.value();

                Object o = activity.getIntent().getExtras().get(value);
                if (o == null) {
                    return;
                }
                Log.i("szjInitIntent", o.toString());

                //允许访问
                field.setAccessible(true);
                try {
                    field.set(activity, o);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

    }


    /**
     * TODO  onClick 监听 方式一[笨拙,时间慢不推荐]
     */
    public void initOnClick1(Activity activity) {
        Class<? extends Activity> cls = activity.getClass();
        Method[] methods = cls.getDeclaredMethods();

        for (Method method : methods) {

            if (method.isAnnotationPresent(szjOnClick.class)) {
                //获取到方法上的所有注解
                Annotation[] annotations = method.getAnnotations();
                //循环所有注解
                for (Annotation annotation : annotations) {
                    if (annotation.annotationType() == szjOnClick.class) {

                        //强制转换为注解类型
                        szjOnClick szjOnClick = (szjOnClick) annotation;

                        //获取到注解中的 id
                        for (int id : szjOnClick.value()) {
                            //获取到 View
                            View view = activity.findViewById(id);
                            //使用动态代理设置点击事件
                            Object o = Proxy.newProxyInstance(activity.getClass().getClassLoader(), new Class[]{View.OnClickListener.class}, (proxy, m, args) -> {
                                //调用属性的方法,设置点击事件回调
                                return method.invoke(activity, args);
                            });
                            view.setOnClickListener((View.OnClickListener) o);
                        }
                    }
                }
            }
        }
    }

    /**
     * TODO  onClick 监听 方式二[推荐]
     */
    public void initOnClick(Activity activity) {
        Class<? extends Activity> cls = activity.getClass();

        //获取到所有方法
        Method[] methods = cls.getDeclaredMethods();

        //遍历所有方法
        for (Method method : methods) {
            //获取到方法上的所有注解
            Annotation[] annotations = method.getAnnotations();

            //循环方法上所有注解
            for (Annotation annotation : annotations) {

                //注解类型
                Class<? extends Annotation> annotationType = annotation.annotationType();
                annotationType.isAnnotationPresent(szjClickType.class);

                Log.i("szj是否检测到有该注解:", annotationType.isAnnotationPresent(szjClickType.class) + "\t");

                //判断是否包含这个注解
                if (annotationType.isAnnotationPresent(szjClickType.class)) {

                    //获取到改注解的实例
                    szjClickType szjClickType = annotationType.getAnnotation(szjClickType.class);

                    assert szjClickType != null;
                    String listenerString = szjClickType.listenerString();
                    Class<?> listenerType = szjClickType.listenerType();

                    try {
                        //利用反射.获取到注解上的 value
                        Method value = annotationType.getDeclaredMethod("value");

                        //获取到注解上的 Id
                        int[] ids = (int[]) value.invoke(annotation);

                        //允许反射访问private属性
                        method.setAccessible(true);

                        //动态代理
                        Object o = Proxy.newProxyInstance(activity.getClassLoader(), new Class[]{listenerType},
                                //调用有 szjClickType 注解上的方法
                                (proxy, md, args) -> method.invoke(activity, args));

                        assert ids != null;
                        //循环到所有的 Id
                        for (int id : ids) {
                            View view = activity.findViewById(id);
                            //通过反射 找到方法名未listenerString 参数为listenerType
                            Method md = view.getClass().getMethod(listenerString, listenerType);
                            //调用该方法
                            md.invoke(view, o);
                        }

                    } catch (Exception e) {

                        Log.i("szjError", e.toString());
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
